/***************************************************************************
 * The Open Armory API is a project to retrieve World of Warcraft(R) 
 * related XML data from The Armory.
 * 
 * The data retrieved via the Open Armory API from The Armory is 
 * proprietary to Blizzard Entertainment, Inc(R).
 * *************************************************************************
 * Copyright (C) 2009 - 2010 Tedla M.B. Brandsema
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 ***************************************************************************/
package net.openarmory.core.domain.validation;

import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.zip.GZIPInputStream;

import net.openarmory.core.config.ConfigurationProperties;
import net.openarmory.core.domain.url.UrlConnectionReader;

import org.apache.log4j.Logger;

import au.com.bytecode.opencsv.CSVReader;

/**
 * The Class <b>RealmStatusRetriever</b>.
 */
public final class RealmStatusRetriever extends UrlConnectionReader {

	/** The log. */
	private static final Logger LOG = Logger
			.getLogger(RealmStatusRetriever.class);

	private static final int KILO_BYTE = 1024;

	/** The config. */
	private ConfigurationProperties config;

	/** The out file. */
	private File outFile;

	/** The realm status list. */
	private List<String[]> realmStatusList = null;

	/**
	 * Instantiates a new realm status retriever.
	 */
	public RealmStatusRetriever() {
		try {
			this.config = ConfigurationProperties.getInstance();
			final String outFilename = this.config.getRealmStatusCSVName();
			this.outFile = new File(this.config.getOutputDir()
					+ File.separatorChar + outFilename);
		} catch (final IOException e) {
			LOG.error("Can not open config file.", e);
		}
	}

	/**
	 * Download the realm status csv and write it to disk.
	 */
	public void downloadRealmStatusCSV() {
		try {

			final URL server = new URL(this.config.getRealmStatusUrl());
			LOG.info("Retrieving realm status archive from URL: "
					+ server.toString());

			final GZIPInputStream gzin = new GZIPInputStream(
					fetchContent(server));
			final File outputDir = new File(this.config.getOutputDir());
			if (!outputDir.exists()) {
				outputDir.mkdir();
			}
			final FileOutputStream fos = new FileOutputStream(this.outFile);
			final byte[] buf = new byte[KILO_BYTE];
			int len;
			while ((len = gzin.read(buf)) > 0) {
				fos.write(buf, 0, len);
			}
			LOG.info("Extracted archive to: " + this.outFile.getAbsolutePath());
			gzin.close();
			fos.flush();
			fos.close();

		} catch (final MalformedURLException e) {
			LOG.error("Malformed URL.", e);
		} catch (final IOException e) {
			LOG.error("Can not write archive.", e);
		}
	}

	/**
	 * Read the realm status csv from disk.
	 * 
	 * @return the list
	 */
	public List<String[]> readRealmStatusCSV() {
		try {
			if (!this.outFile.exists()) {
				downloadRealmStatusCSV();
			}
			final CSVReader reader = new CSVReader(new FileReader(this.outFile));
			this.realmStatusList = reader.readAll();
		} catch (final IOException e) {
			LOG.error("Could not open CSV file", e);
		}
		return this.realmStatusList;
	}

	/**
	 * Retrieve all realms from the csv file and read them into Realm objects
	 * contained in a List.
	 * 
	 * @return the list< realm>
	 */
	public List<Realm> retrieveRealms() {
		final List<Realm> realmList = new ArrayList<Realm>();

		if (this.realmStatusList == null) {
			readRealmStatusCSV();
		}

		final Iterator<String[]> itr = this.realmStatusList.iterator();

		boolean isFirstCSVLine = true;

		while (itr.hasNext()) {
			final String[] csvLine = itr.next();
			if (!isFirstCSVLine) {
				realmList.add(new Realm(csvLine));
			} else {
				isFirstCSVLine = false;
			}
		}
		return realmList;
	}
}
